package com.dd.cloud.user.service.phar.pharservice;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.dd.cloud.common.constants.PharConstants;
import com.dd.cloud.common.constants.PresConstants;
import com.dd.cloud.common.enums.ZkExceptionEnum;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.interceptor.UserInterceptor;
import com.dd.cloud.common.utils.CalendarUtil;
import com.dd.cloud.common.utils.JsonUtils;
import com.dd.cloud.common.utils.SerialNumberUtils;
import com.dd.cloud.common.vo.LoginInfo;
import com.dd.cloud.user.DTO.CallbackPresStatusReq;
import com.dd.cloud.user.DTO.CancelPresReq;
import com.dd.cloud.user.DTO.CommonParamReq;
import com.dd.cloud.user.DTO.hjt.DrugDTO;
import com.dd.cloud.user.DTO.hjt.HjtStatusReportReq;
import com.dd.cloud.user.DTO.hjt.PresDTO;
import com.dd.cloud.user.DTO.hjt.SendPresDTO;
import com.dd.cloud.user.entity.doctor.PatientMedCard;
import com.dd.cloud.user.entity.order.OrderPay;
import com.dd.cloud.user.entity.phar.Pharmacy;
import com.dd.cloud.user.entity.phar.PharmacyDocking;
import com.dd.cloud.user.entity.pres.PresHjtDetail;
import com.dd.cloud.user.entity.pres.PresHjtPharRoam;
import com.dd.cloud.user.entity.pres.PresPrescription;
import com.dd.cloud.user.entity.pres.PresPretrialDrugs;
import com.dd.cloud.user.enums.ExceptionEnum;
import com.dd.cloud.user.mq.MQConfig;
import com.dd.cloud.user.mq.RabbitSend;
import com.dd.cloud.user.req.phar.PresCreateCreamFormulaReq;
import com.dd.cloud.user.req.pres.PresCreateHjtReq;
import com.dd.cloud.user.req.pres.PresCreateReq;
import com.dd.cloud.user.req.pres.PresPatientAddrReq;
import com.dd.cloud.user.service.doctor.IDoctorEquityService;
import com.dd.cloud.user.service.log.ILogErrorService;
import com.dd.cloud.user.service.order.IOrderPayService;
import com.dd.cloud.user.service.phar.IPharmacyDockingService;
import com.dd.cloud.user.service.phar.IPharmacyService;
import com.dd.cloud.user.service.pres.IPresHjtDetailService;
import com.dd.cloud.user.service.pres.IPresHjtPharRoamService;
import com.dd.cloud.user.service.pres.IPresPrescriptionService;
import com.dd.cloud.user.service.pres.IPresPretrialDrugsService;
import com.dd.cloud.user.service.sms.ISmsService;
import com.dd.cloud.user.vo.DelayMqVo;
import com.dd.cloud.user.vo.HjtResponseVo;
import com.dd.cloud.user.vo.PharResponseVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.List;

/**
 * @Description: 宏济堂药房操作，
 * @Author: czg
 * @Date: 2022/11/25 17:20
 * @Version: 1.0.0
 */
@Service
@Slf4j
public class HjtPharService extends PharAbstractService {
    @Autowired
    private IPresHjtDetailService presHjtDetailService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private IOrderPayService orderPayService;
    @Autowired
    private ILogErrorService logErrorService;
    @Autowired
    private IPresPrescriptionService presPrescriptionService;
    @Autowired
    private IPharmacyService pharmacyService;
    @Autowired
    private IPresPretrialDrugsService presPretrialDrugsService;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private IPresHjtPharRoamService presHjtPharRoamService;
    @Autowired
    private IPharmacyDockingService pharmacyDockingService;
    @Autowired
    private RabbitSend rabbitSend;
    //蜂蜜价格 单位分
    private final Integer prsPrice = 15000;
    private final String unit = "kg";
    @Autowired
    private ISmsService smsService;

    /**
     * @param req: 处方详情
     * @return void
     * @author czg
     * @description 宏济堂添加处方详情
     * @date 2022/11/26 17:44
     */
    @Override
    public void addPresDetail(PresCreateReq req, PatientMedCard medCard) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        PresCreateHjtReq hjtReq = (PresCreateHjtReq) req;
        PresHjtDetail detail = new PresHjtDetail();
        BeanUtils.copyProperties(hjtReq, detail);
        detail.setDiagresult(req.getDisease());
        detail.setSex(1);
        if ("女".equals(medCard.getSex())) {
            detail.setSex(2);
        }
        Integer age = CalendarUtil.getAge(medCard.getBirthDate());
        detail.setAge(age == null ? null : String.valueOf(age));
        detail.setName(medCard.getName());
        detail.setTencode(req.getTencode());
        detail.setHospitalname("广州阿康中医诊所有限公司");
        detail.setHospitalkey("zk");
        detail.setDrugcount(req.getTcms().size());
        detail.setDecscheme(2);
        detail.setSoakwater(2000);
        detail.setSoaktime(30);
        detail.setMoney(hjtReq.getMoney());
        detail.setLabelnum(req.getAllDose() * req.getDayDose() + 2);
        detail.setDoctor(loginInfo.getName());
        detail.setPayment(hjtReq.getPayment());
        detail.setOutpatientindex(SerialNumberUtils.getInstance().getSerialNumber(redisTemplate, "CF"));
        detail.setCreateDate(LocalDateTime.now());
        if (req.getPresType() == PresConstants.DrugsProcessingType.FOURTEEN) {
            detail.setRemark(detail.getRemark() + ",加工类型:超微打粉,每包" + req.getPackagenum() + "g");
        }
        if (req.getPresType() == PresConstants.DrugsProcessingType.TWELVE || req.getPresType() == PresConstants.DrugsProcessingType.FIFTEEN) {
            detail.setRemark(detail.getRemark() + ",每包" + req.getPackagenum() + "g");
        }
        if (req.getPresType() == PresConstants.DrugsProcessingType.TEN || req.getPresType() == PresConstants.DrugsProcessingType.ELEVEN) {
            detail.setRemark(detail.getRemark() + ",每包" + req.getPackagenum() + "g" + ",目数:" + req.getNum() + "目");
        }
        if (req.getPresType() == PresConstants.DrugsProcessingType.EIGHT) {
            //辅料添加到备注
            List<PresCreateCreamFormulaReq> list = req.getCreamFormulaReqs();
            if (!CollectionUtils.isEmpty(list)) {
                StringBuilder sb = new StringBuilder();
                sb.append("辅料:");
                for (int i = 0; i < list.size(); i++) {
                    PresCreateCreamFormulaReq res = list.get(i);
                    String remark = "[名称:" + res.getName() + ",重量:" + res.getWeight() + ",单位:" + res.getUnit() + "] ";
                    sb.append(remark);
                }
                String res = sb.toString();
                detail.setRemark(detail.getRemark() + "," + res + "," + "每包" + req.getPackagenum() + "g");
            }
        } else if (req.getPresType() == PresConstants.DrugsProcessingType.SEVEN || req.getPresType() == PresConstants.DrugsProcessingType.SIX) {
            log.info("蜜丸/水蜜丸转换成kg====>" + req.getWeightKg());
            List<PresCreateCreamFormulaReq> list = req.getCreamFormulaReqs();
            PresCreateCreamFormulaReq res = list.get(0);
            String remark = "[名称:" + res.getName() + ",重量:" + res.getWeight() + ",单位:" + res.getUnit() + "]";
            detail.setRemark(detail.getRemark() + "," + remark + "," + "每次" + req.getPackagenum() + "g");
        }
        detail.setAddress(detail.getDtbaddress());
        boolean i = presHjtDetailService.saveOrUpdate(detail);
        if (!i) {
            throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "处方信息保存失败");
        }
    }

    /**
     * @param pay: 支付的订单
     * @return void
     * @author czg
     * @description 发送处方到药房
     * @date 2022/11/26 17:44
     */
    @Override
    public boolean sendPresToPhar(OrderPay pay) {
        boolean succ = false;
        if (StringUtils.isBlank(pay.getServerNo())) {
            //没有处方编码 数据异常, 退款
            orderPayService.refund(pay.getOrderNo(), 0);
            logErrorService.presBackLog("没有处方编码-数据异常, 退款", "处方发送到药房异常", "tencode=" + pay.getServerNo());
            return succ;
        }
        PresPrescription presPrescription = presPrescriptionService.getById(pay.getServerNo());
        if (presPrescription == null) {
            presPrescription.setStatus(PresConstants.PresStatus.SENDPHARMERROR);
            presPrescriptionService.updateById(presPrescription);
            //处方为空, 数据异常, 退款
//            orderPayService.refund(pay.getOrderNo(), 0);
            logErrorService.presBackLog("处方为空-数据异常, 退款", "处方发送到药房异常", "tencode=" + pay.getServerNo());
            return succ;
        }
        if (presPrescription.getStatus() == PresConstants.PresStatus.SENDPHARM) {
            //处方已发送到药房, 此为重复回调
            log.info("处方已发送到药房, 此为重复回调");
            return succ;
        }
        PresHjtDetail detail = presHjtDetailService.getById(pay.getServerNo());
        if (detail == null) {
            //没有处方详情, 数据异常, 退款
            presPrescription.setStatus(PresConstants.PresStatus.SENDPHARMERROR);
            presPrescriptionService.updateById(presPrescription);
//            orderPayService.refund(pay.getOrderNo(), 0);
            logErrorService.presBackLog("没有处方详情-数据异常, 退款", "处方发送到药房异常", "tencode=" + pay.getServerNo());
            return succ;
        }
        Pharmacy pharmacy = pharmacyService.getById(presPrescription.getPharmId());
        if (pharmacy == null) {
            //药房为空, 数据异常 ,退款
//            orderPayService.refund(pay.getOrderNo(), 0);
            presPrescription.setStatus(PresConstants.PresStatus.SENDPHARMERROR);
            presPrescriptionService.updateById(presPrescription);
            logErrorService.presBackLog("药房为空-数据异常", "处方发送到药房异常", "tencode=" + pay.getServerNo());
            return succ;
        }
        QueryWrapper<PharmacyDocking> qd = new QueryWrapper<>();
        qd.lambda().eq(PharmacyDocking::getPharId, pharmacy.getId()).eq(PharmacyDocking::getStatus, PharConstants.DockingStatus.NOMER);
        PharmacyDocking pharmacyDocking = pharmacyDockingService.getOne(qd);
        if (pharmacyDocking == null) {
            //药房为空, 数据异常 ,退款
            presPrescription.setStatus(PresConstants.PresStatus.SENDPHARMERROR);
            presPrescriptionService.updateById(presPrescription);
//            orderPayService.refund(pay.getOrderNo(), 0);
            logErrorService.presBackLog("药房对接信息为空-数据异常, 退款", "处方发送到康美药房异常", "pharId=" + pharmacy.getId());
            return succ;
        }
        QueryWrapper<PresPretrialDrugs> qw = new QueryWrapper<>();
        qw.lambda().eq(PresPretrialDrugs::getTencode, presPrescription.getTencode()).eq(PresPretrialDrugs::getStatus, PresConstants.PresDrugsStatus.NOMER);
        List<PresPretrialDrugs> drugsList = presPretrialDrugsService.list(qw);
        if (drugsList == null || drugsList.isEmpty()) {
            //没有处方药品, 数据异常, 退款
//            orderPayService.refund(pay.getOrderNo(), 0);
            presPrescription.setStatus(PresConstants.PresStatus.SENDPHARMERROR);
            presPrescriptionService.updateById(presPrescription);
            logErrorService.presBackLog("没有处方药品-数据异常", "处方发送到药房异常", "tencode=" + pay.getServerNo());
            return succ;
        }
        PresDTO presDTO = new PresDTO();
        BeanUtils.copyProperties(detail, presDTO);
        presDTO.setPspnum(presPrescription.getTencode());
        presDTO.setYizhu(presPrescription.getAdvice());
        presDTO.setDose(presPrescription.getAllDose());
        presDTO.setTakenum(presPrescription.getDoseNum());
        presDTO.setDelnum("zk001");
        presDTO.setPtype("0");
        presDTO.setProcedurejump(0);
        presDTO.setMoney(detail.getMoney() / 100.0);
        List<DrugDTO> list = new LinkedList<>();
        for (PresPretrialDrugs drugs : drugsList) {
            DrugDTO drugDTO = new DrugDTO();
            BeanUtils.copyProperties(drugs, drugDTO);
            drugDTO.setDrugname(drugs.getHerbName());
            drugDTO.setTienum(presPrescription.getAllDose());
            drugDTO.setDrugweight(drugDTO.getDrugallnum() * drugDTO.getTienum());
            drugDTO.setDrugposition(drugs.getSpecification());
            drugDTO.setDrugdescription(drugs.getDecocting());
            list.add(drugDTO);
        }
        String presUrl = pharmacyDocking.getServicesUrl();
        SendPresDTO sendPresDTO = new SendPresDTO();
        sendPresDTO.setPrescription(presDTO);
        sendPresDTO.setDrug(list);
        String params = JsonUtils.objectToStr(sendPresDTO);
        HttpHeaders requestHeaders = new HttpHeaders();
        //提交参数设置
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("jsondhy", params);
        map.add("url", presUrl);
        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<MultiValueMap<String, String>>(map, requestHeaders);
        log.info("宏济堂发送参数:{}", map);
        log.debug("宏济堂发送url:{}", presUrl);
        String data = null;

        /**
         * 2023-12-25 此处代码,由于云服务器71网段无法访问宏济堂的接口, 其他网段可以, 暂时找不到问题,
         * 这里用代理, 请求代理到116.205.164.236公网服务器转发到宏济堂接口, 如果云服务网络恢复可以通信, 这里代理可以去掉
         */
//        RestTemplate restTemplates = new RestTemplate();
//        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
//        requestFactory.setProxy(
//                new Proxy(
//                        Proxy.Type.HTTP,
//                        //设置代理服务
//                        new InetSocketAddress("116.205.164.236", 8080)
//                )
//        );
//        restTemplates.setRequestFactory(requestFactory);
        String sendUrl = "http://192.168.0.181:8080/drugView/send";
        try {
            //发送处方到药房
            data = restTemplate.postForObject(sendUrl, entity, String.class);
        } catch (Exception e) {
            e.printStackTrace();
            presPrescription.setStatus(PresConstants.PresStatus.SENDPHARMERROR);
            presPrescriptionService.updateById(presPrescription);
            logErrorService.presBackLog("处方发送失败", "处方发送到宏济堂药房异常", "jsonBody=" + data);
            return succ;
        }
        if (data == null) {
            presPrescription.setStatus(PresConstants.PresStatus.SENDPHARMERROR);
            presPrescriptionService.updateById(presPrescription);
            logErrorService.presBackLog("处方返回为空", "处方发送到宏济堂药房异常", "jsonBody=" + data);
            return succ;
        }
        //返回的json首尾会带" 去掉
        if (data.startsWith("\"")) {
            data = data.substring(1);
        }
        if (data.endsWith("\"")) {
            data = data.substring(0, data.length() - 1);
        }
        data = data.replaceAll("\\\\", "");
        log.info("药房返回:{}", data);
        HjtResponseVo hjtResponseVo;
        try {
            hjtResponseVo = JsonUtils.parse(data, HjtResponseVo.class);
        } catch (Exception e) {
            presPrescription.setStatus(PresConstants.PresStatus.SENDPHARMERROR);
            presPrescriptionService.updateById(presPrescription);
//            orderPayService.refund(pay.getOrderNo(), 0);
            logErrorService.presBackLog("药房返回数据json解析失败, 退款", "处方发送到药房异常", "jsonBody=" + data);
            return succ;
        }
        if (!hjtResponseVo.getDhy_error_code().equals("0")) {
            //接口返回异常 退款
            presPrescription.setStatus(PresConstants.PresStatus.SENDPHARMERROR);
            presPrescriptionService.updateById(presPrescription);
//            orderPayService.refund(pay.getOrderNo(), 0);
            logErrorService.presBackLog("药房返回状态码异常, 退款", "处方发送到药房异常", "jsonBody=" + data);
            return succ;
        }
        presPrescription.setStatus(PresConstants.PresStatus.SENDPHARM);
        presPrescription.setUpdateDate(LocalDateTime.now());
        boolean flag = presPrescriptionService.updateById(presPrescription);
        if (!flag) {
            logErrorService.presBackLog("发送处方到药房成功, 处方更新失败", "处方发送到药房异常", "jsonBody=" + presPrescription);
            return succ;
        }
        succ = true;
        return succ;
    }

    /**
     * @param req:
     * @return void
     * @author czg
     * @description 取消处方接口
     * @date 2022/12/2 9:48
     */
    @Override
    public void cancelPres(CancelPresReq req) {
        log.info("宏济堂无取消处方接口, 不支持取消处方");
        throw new ZekeException(ZkExceptionEnum.CANCEL_PRES_ERROR, "宏济堂药房不支持线上取消处方,请联系管理员线下取消处方");
    }

    @Autowired
    private IDoctorEquityService doctorEquityService;


    /**
     * @param :
     * @return void
     * @author czg
     * @description 处方状态回调
     * @date 2022/11/26 17:42
     */
    @Override
    public PharResponseVo presCallback(CallbackPresStatusReq req) {
        HjtResponseVo responseVo = new HjtResponseVo();
        HjtStatusReportReq hjtReq = (HjtStatusReportReq) req.toStatusPojo();
        if (hjtReq == null || hjtReq.getPrenum() == null) {
            responseVo.setDhy_error_code("40001");
            responseVo.setDhy_error_msg("参数数据为空");
            return responseVo;
        }
        QueryWrapper<PresPrescription> qw = new QueryWrapper<>();
        qw.lambda().eq(PresPrescription::getTencode, hjtReq.getPrenum()).ne(PresPrescription::getStatus, PresConstants.PresStatus.DEL);
        PresPrescription presPrescription = presPrescriptionService.getOne(qw);
        if (presPrescription == null) {
            responseVo.setDhy_error_code("40001");
            responseVo.setDhy_error_msg("处方号不存在");
            return responseVo;
        }
        int status;
        switch (hjtReq.getPrestatus()) {
            case PresConstants.HjtPresStatus.ADJUST:
                status = PresConstants.PresStatus.ADJUST;
                break;
            case PresConstants.HjtPresStatus.AUDIT:
                status = PresConstants.PresStatus.AUDIT;
                break;
            case PresConstants.HjtPresStatus.BMED:
                status = PresConstants.PresStatus.BMED;
                break;
            case PresConstants.HjtPresStatus.REVIEW:
                status = PresConstants.PresStatus.REVIEW;
                break;
            case PresConstants.HjtPresStatus.TISANES:
                status = PresConstants.PresStatus.TISANES;
                break;
            case PresConstants.HjtPresStatus.PACK:
                status = PresConstants.PresStatus.PACK;
                break;
            default:
                status = PresConstants.PresStatus.DELIVERY;
                presPrescription.setExpressno(hjtReq.getExpressno());
                presPrescription.setExpresscompany(hjtReq.getExpresscompany());
                hjtReq.setOperatestarttime(hjtReq.getOperateendtime());
                hjtReq.setOperateendtime(null);
                DelayMqVo<String> delayMqVo = new DelayMqVo<>();
                delayMqVo.setT(presPrescription.getTencode());
                delayMqVo.setType(DelayMqVo.DelayMqVoType.PRES_COMPLETE);
                //毫秒级 7天
                long ms = 1000 * 60 * 60 * 24 * 7;
                rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo, ms);
                smsService.sendDeliveryPres(presPrescription.getTencode(), presPrescription.getDoctorId(), presPrescription.getName(), hjtReq.getExpressno(), hjtReq.getExpresscompany());
                LambdaQueryWrapper<OrderPay> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(OrderPay::getServerNo, presPrescription.getTencode()).eq(OrderPay::getStatus, 2);
                OrderPay orderPay = orderPayService.getOne(queryWrapper);
                if (orderPay != null) {
                    doctorEquityService.saveDoctorEquity(orderPay, 2);
                }
                break;
        }
        if (presPrescription.getStatus() == status) {
            //重复请求
            responseVo.setDhy_error_code("0");
            responseVo.setDhy_error_msg("OK");
            return responseVo;
        }
        presPrescription.setUpdateDate(LocalDateTime.now());
        presPrescription.setStatus(status);
        PresHjtPharRoam presHjtPharRoam = new PresHjtPharRoam();
        BeanUtils.copyProperties(hjtReq, presHjtPharRoam);
        presHjtPharRoam.setTencode(presPrescription.getTencode());
        presHjtPharRoam.setCreateDate(LocalDateTime.now());
        presHjtPharRoam.setStatus(PresConstants.RoamStatus.NOMER);
        boolean flag = presHjtPharRoamService.save(presHjtPharRoam);
        if (!flag) {
            responseVo.setDhy_error_code("40001");
            responseVo.setDhy_error_msg("处方流转保存失败");
            return responseVo;
        }
        flag = presPrescriptionService.updateById(presPrescription);
        if (!flag) {
            responseVo.setDhy_error_code("40001");
            responseVo.setDhy_error_msg("处方流转修改状态失败");
            return responseVo;
        }
        responseVo.setDhy_error_code("0");
        responseVo.setDhy_error_msg("OK");
        return responseVo;
    }

    @Override
    public PharResponseVo expressCallback(CommonParamReq req) {
        log.info("宏济堂无物流回调接口");
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePresPatientAddrInfo(PresPatientAddrReq req) {
        UpdateWrapper<PresHjtDetail> uw = new UpdateWrapper<>();
        uw.lambda().eq(PresHjtDetail::getTencode, req.getTencode());
        uw.lambda().set(PresHjtDetail::getDtbcompany, req.getReceiver());
        uw.lambda().set(PresHjtDetail::getDtbphone, req.getMobileNumber());
        uw.lambda().set(PresHjtDetail::getDtbaddress, req.getProvince() + req.getCity() + req.getDistrict() + req.getAddr());
        boolean flag = presHjtDetailService.update(uw);
        if (!flag) {
            throw new ZekeException(400, "修改处方收货人信息失败");
        }
    }
}
